package main

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"gitee.com/gbat/nats-demo/common"
	"github.com/nats-io/nats.go"
	uuid "github.com/satori/go.uuid"
	"log"
	"os"
	"strconv"
	"time"
)

type ST struct {
	Remains int
	Version int64
}

var (
	s      = &ST{Remains: 0, Version: time.Now().UnixNano()}
	bucket = "test_kv"
	key    = "test_key"
	count  = 1000
)

func (st *ST) Unmarshal(value []byte) {
	err := json.Unmarshal(value, &st)
	if err != nil {
		log.Fatalln(err)
	}
}

func (st *ST) Marshal() []byte {
	v, err := json.Marshal(st)
	if err != nil {
		log.Fatalln(err)
	}
	return v
}

func main() {
	opts := []nats.Option{nats.Name("NATS Sample Queue Subscriber")}
	opts = common.SetupConnOptions(opts)
	// Connect to NATS
	nc, err := nats.Connect(nats.DefaultURL, opts...)
	if err != nil {
		log.Fatalln(err)
	}
	// Create JetStream Context
	js, err := nc.JetStream()
	if err != nil {
		log.Fatalln(err)
	}

	// region test
	//kv2,err:=js.CreateKeyValue(&nats.KeyValueConfig{Bucket:uuid.NewV4().String(),History:0, TTL: 0}) //单节点140ops/s
	//if err != nil {
	// log.Fatalln(err)
	//}
	//log.Println(kv2.Bucket())
	kv2, err := js.KeyValue("bf594d2c-f96c-4e8c-84f3-b482d28efc40")
	if err != nil {
		log.Fatalln(err)
	}
	//keys2,err:=kv2.Keys()
	//if err != nil {
	//  log.Fatalln(err)
	//}
	//for _,key:=range  keys2{
	// err=kv2.Purge(key)
	// if err!=nil{
	//     log.Fatalln(err)
	// }
	//}
	err = kv2.PurgeDeletes()
	if err != nil {
		log.Fatalln(err)
	}
	//for i:=0;i<10000 ;i++  {
	//    _,err:=kv2.PutString(uuid.NewV4().String(),strconv.Itoa(i))
	//    if err!=nil{
	//        log.Fatalln(err)
	//    }
	//}
	//var keys2 []string
	//st2:=time.Now()
	//for i:=0;i<10000;i++  {
	//    keys2,err=kv3.Keys()
	//    if err != nil {
	//        log.Fatalln(err)
	//    }
	//}
	//log.Println("Keys---key length：", len(keys2),"request:10000","cost:",time.Since(st2).Milliseconds(),"ms")//2 ops/sec
	//st2:=time.Now()
	//var status nats.KeyValueStatus
	//for i:=0;i<10000;i++  {
	//    status,err=kv2.Status() //没有场景下能用到，不知道是什么用处
	//    if err != nil {
	//        log.Fatalln(err)
	//    }
	//}
	//log.Println("Status---value length：",status.Values(),"request:10000","cost:",time.Since(st2).Milliseconds(),"ms")  //需要设置history为1 确保key的数量和value数量一致，7k ops/sec
	//var val2 nats.KeyValueEntry
	//for i:=0;i<10000;i++  {
	//    val2,err=kv2.Get(keys2[1000])
	//    if err != nil {
	//        log.Fatalln(err)
	//    }
	//}
	//log.Println("Get---key value：",string(val2.Value()),"request:10000")
	os.Exit(0)
	// endregion

	st := time.Now()
	var kvs []nats.KeyValue
	for i := 0; i < 10000; i++ {
		kv, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: uuid.NewV4().String(), History: 2, TTL: 0}) //单节点140ops/s
		if err != nil {
			log.Fatalln(err)
		}
		kvs = append(kvs, kv)
	}

	log.Println("CreateKeyValue---kv 长度：", len(kvs), "cost:", time.Since(st).Milliseconds(), "ms", "request:10000")
	//os.Exit(0)
	st = time.Now()
	for i := 0; i < 10000; i++ {
		_, err := kvs[100].PutString(uuid.NewV4().String(), strconv.Itoa(i))
		if err != nil {
			log.Fatalln(err)
		}
	}
	log.Println("PutString---", "cost:", time.Since(st).Milliseconds(), "ms", "request:10000")

	st = time.Now()
	keys, err := kvs[100].Keys()
	if err != nil {
		log.Fatalln(err)
	}
	log.Println("Keys---len:", len(keys), "cost:", time.Since(st).Milliseconds(), "ms", "request:10000")

	st = time.Now()
	var val nats.KeyValueEntry
	for i := 0; i < 10000; i++ {
		val, err = kvs[100].Get(keys[1000])
		if err != nil {
			log.Fatalln(err)
		}
	}

	//log.Println("result:",BytesToInt(val.Value()))
	log.Println("Get---key value：", string(val.Value()), "cost:", time.Since(st).Milliseconds(), "ms", "request:10000")

	//st=time.Now()
	//for i:=0;i<10000;i++  {
	//    err=kvs[100].Purge(keys[i])
	//    if err != nil {
	//        log.Fatalln(err)
	//    }
	//}
	////log.Println("result:",BytesToInt(val.Value()))
	//log.Println("Purge---key 长度：",len(keys),"cost:",time.Since(st).Milliseconds(),"ms","request:10000")
	os.Exit(0)

	//_,err=kv.Create(key,s.Marshal())
	//if err!=nil{
	//   log.Fatalln(err)
	//}
	//start:=time.Now()
	//var wg sync.WaitGroup
	//wg.Add(count)
	//for i:=0;i<count ;i++  {
	//    go func(i int) {
	// retry: r,err:=kv.Get(key)
	//        if err!=nil{
	//            log.Fatalln(err)
	//        }
	//        s.Unmarshal(r.Value())
	//        s.Remains++
	//        _,err=kv.Update(key,s.Marshal(),r.Revision())
	//        if err!=nil{
	//            log.Println(err)
	//            time.Sleep(5)
	//            goto retry
	//        }
	//        wg.Done()
	//    }(i)
	//}
	//wg.Wait()
	//r,err:=kv.Get(key)
	//if err!=nil{
	//    log.Fatalln(err)
	//}
	//s.Unmarshal(r.Value())
	//log.Println("finished:",s.Remains,",cost:",time.Since(start).Milliseconds(),"ms")
}

//整形转换成字节
func IntToBytes(n int) []byte {
	x := int32(n)
	bytesBuffer := bytes.NewBuffer([]byte{})
	binary.Write(bytesBuffer, binary.BigEndian, x)
	return bytesBuffer.Bytes()
}

//字节转换成整形
func BytesToInt(b []byte) int {
	bytesBuffer := bytes.NewBuffer(b)

	var x int32
	binary.Read(bytesBuffer, binary.BigEndian, &x)

	return int(x)
}
